import { is } from "../../util/ModelUtil";
import { isAny } from "../modeling/util/ModelingUtil";

import {
  getMid,
  asTRBL,
  getOrientation
} from "diagram-js/lib/layout/LayoutUtil";

import {
  findFreePosition,
  generateGetNextPosition,
  getConnectedDistance
} from "diagram-js/lib/features/auto-place/AutoPlaceUtil";

/**
 * Find the new position for the target element to
 * connect to source.
 *
 * @param  {djs.model.Shape} source
 * @param  {djs.model.Shape} element
 *
 * @return {Point}
 */
export function getNewShapePosition(source, element) {
  if (is(element, "bpmn:TextAnnotation")) {
    return getTextAnnotationPosition(source, element);
  }

  if (isAny(element, ["bpmn:DataObjectReference", "bpmn:DataStoreReference"])) {
    return getDataElementPosition(source, element);
  }

  if (is(element, "bpmn:FlowNode")) {
    return getFlowNodePosition(source, element);
  }
}

/**
 * Always try to place element right of source;
 * compute actual distance from previous nodes in flow.
 */
export function getFlowNodePosition(source, element) {
  var sourceTrbl = asTRBL(source);
  var sourceMid = getMid(source);

  var horizontalDistance = getConnectedDistance(source, {
    filter: function(connection) {
      return is(connection, "bpmn:SequenceFlow");
    }
  });

  var margin = 30,
    minDistance = 80,
    orientation = "left";

  if (is(source, "bpmn:BoundaryEvent")) {
    orientation = getOrientation(source, source.host, -25);

    if (orientation.indexOf("top") !== -1) {
      margin *= -1;
    }
  }

  var position = {
    x: sourceTrbl.right + horizontalDistance + element.width / 2,
    y: sourceMid.y + getVerticalDistance(orientation, minDistance)
  };

  var nextPositionDirection = {
    y: {
      margin: margin,
      minDistance: minDistance
    }
  };

  return findFreePosition(
    source,
    element,
    position,
    generateGetNextPosition(nextPositionDirection)
  );
}

function getVerticalDistance(orientation, minDistance) {
  if (orientation.indexOf("top") != -1) {
    return -1 * minDistance;
  } else if (orientation.indexOf("bottom") != -1) {
    return minDistance;
  } else {
    return 0;
  }
}

/**
 * Always try to place text annotations top right of source.
 */
export function getTextAnnotationPosition(source, element) {
  var sourceTrbl = asTRBL(source);

  var position = {
    x: sourceTrbl.right + element.width / 2,
    y: sourceTrbl.top - 50 - element.height / 2
  };

  var nextPositionDirection = {
    y: {
      margin: -30,
      minDistance: 20
    }
  };

  return findFreePosition(
    source,
    element,
    position,
    generateGetNextPosition(nextPositionDirection)
  );
}

/**
 * Always put element bottom right of source.
 */
export function getDataElementPosition(source, element) {
  var sourceTrbl = asTRBL(source);

  var position = {
    x: sourceTrbl.right - 10 + element.width / 2,
    y: sourceTrbl.bottom + 40 + element.width / 2
  };

  var nextPositionDirection = {
    x: {
      margin: 30,
      minDistance: 30
    }
  };

  return findFreePosition(
    source,
    element,
    position,
    generateGetNextPosition(nextPositionDirection)
  );
}
